package com.cencat.merchant.service.impl;

import com.cencat.merchant.entity.DispatchRecordEntity;
import com.cencat.merchant.entity.DriverEntity;
import com.cencat.merchant.entity.DriverMerchantBindEntity;
import com.cencat.merchant.mapper.DispatchRecordMapper;
import com.cencat.merchant.mapper.DriverMapper;
import com.cencat.merchant.mapper.DriverMerchantBindMapper;
import com.cencat.merchant.service.DispatchAlgorithmService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 智能派单算法服务实现类
 * 
 * @author cencat
 * @since 2024
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DispatchAlgorithmServiceImpl implements DispatchAlgorithmService {
    
    private final DriverMapper driverMapper;
    private final DispatchRecordMapper dispatchRecordMapper;
    private final DriverMerchantBindMapper driverMerchantBindMapper;
    
    // 地球半径(公里)
    private static final double EARTH_RADIUS = 6371.0;
    
    @Override
    public Long distancePriorityDispatch(Long orderId, List<DriverEntity> availableDrivers, Map<String, Double> orderLocation) {
        log.info("执行距离优先派单算法，订单ID: {}, 可用司机数量: {}", orderId, availableDrivers.size());
        
        if (availableDrivers.isEmpty()) {
            log.warn("没有可用司机，订单ID: {}", orderId);
            return null;
        }
        
        // 计算每个司机与订单的距离，选择最近的司机
        DriverEntity nearestDriver = availableDrivers.stream()
            .min(Comparator.comparing(driver -> {
                Map<String, Double> driverLocation = Map.of(
                    "latitude", driver.getCurrentLatitude().doubleValue(),
                    "longitude", driver.getCurrentLongitude().doubleValue()
                );
                return calculateDistance(driverLocation, orderLocation);
            }))
            .orElse(null);
        
        return nearestDriver != null ? nearestDriver.getId() : null;
    }
    
    @Override
    public Long ratingPriorityDispatch(Long orderId, List<DriverEntity> availableDrivers, Double minRating) {
        log.info("执行评分优先派单算法，订单ID: {}, 最低评分要求: {}", orderId, minRating);
        
        // 筛选满足最低评分要求的司机，按评分降序排列
        List<DriverEntity> qualifiedDrivers = availableDrivers.stream()
            .filter(driver -> driver.getServiceRating().doubleValue() >= minRating)
            .sorted(Comparator.comparing(DriverEntity::getServiceRating).reversed())
            .collect(Collectors.toList());
        
        if (qualifiedDrivers.isEmpty()) {
            log.warn("没有满足评分要求的司机，订单ID: {}, 最低评分: {}", orderId, minRating);
            return null;
        }
        
        return qualifiedDrivers.get(0).getId();
    }
    
    @Override
    public Long loadBalanceDispatch(Long orderId, List<DriverEntity> availableDrivers) {
        log.info("执行负载均衡派单算法，订单ID: {}, 可用司机数量: {}", orderId, availableDrivers.size());
        
        if (availableDrivers.isEmpty()) {
            return null;
        }
        
        // 获取每个司机当前的订单数量，选择负载最轻的司机
        DriverEntity lightestLoadDriver = availableDrivers.stream()
            .min(Comparator.comparing(driver -> {
                // 这里应该查询司机当前的订单数量，暂时使用随机数模拟
                return getCurrentOrderCount(driver.getId());
            }))
            .orElse(null);
        
        return lightestLoadDriver != null ? lightestLoadDriver.getId() : null;
    }
    
    @Override
    public Long exclusiveBindDispatch(Long orderId, Long merchantId, List<DriverEntity> availableDrivers) {
        log.info("执行专属绑定派单算法，订单ID: {}, 商家ID: {}", orderId, merchantId);
        
        // 查询与商家绑定的司机
        List<DriverMerchantBindEntity> bindings = driverMerchantBindMapper.selectByMerchantId(merchantId);
        Set<Long> boundDriverIds = bindings.stream()
            .filter(bind -> bind.getBindType() == 1) // 1-专属绑定
            .map(DriverMerchantBindEntity::getDriverId)
            .collect(Collectors.toSet());
        
        // 优先选择专属绑定的司机
        Optional<DriverEntity> boundDriver = availableDrivers.stream()
            .filter(driver -> boundDriverIds.contains(driver.getId()))
            .findFirst();
        
        if (boundDriver.isPresent()) {
            return boundDriver.get().getId();
        }
        
        // 如果没有专属司机，选择普通绑定的司机
        Set<Long> normalBindDriverIds = bindings.stream()
            .filter(bind -> bind.getBindType() == 0) // 0-普通绑定
            .map(DriverMerchantBindEntity::getDriverId)
            .collect(Collectors.toSet());
        
        Optional<DriverEntity> normalDriver = availableDrivers.stream()
            .filter(driver -> normalBindDriverIds.contains(driver.getId()))
            .findFirst();
        
        return normalDriver.map(DriverEntity::getId).orElse(null);
    }
    
    @Override
    public Long intelligentDispatch(Long orderId, Long merchantId, List<DriverEntity> availableDrivers, 
                                  Map<String, Double> orderLocation, Map<String, Double> algorithmWeights) {
        log.info("执行综合智能派单算法，订单ID: {}, 商家ID: {}", orderId, merchantId);
        
        if (availableDrivers.isEmpty()) {
            return null;
        }
        
        // 计算每个司机的综合匹配度分数
        DriverEntity bestDriver = availableDrivers.stream()
            .max(Comparator.comparing(driver -> 
                calculateMatchScore(driver, orderId, orderLocation, algorithmWeights)))
            .orElse(null);
        
        return bestDriver != null ? bestDriver.getId() : null;
    }
    
    @Override
    public List<DriverEntity> getAvailableDrivers(Long orderId, Long merchantId, Map<String, Double> orderLocation, Double maxDistance) {
        log.info("获取可用司机列表，订单ID: {}, 商家ID: {}, 最大距离: {}km", orderId, merchantId, maxDistance);
        
        // 查询在线且空闲的司机
        List<DriverEntity> onlineDrivers = driverMapper.selectOnlineDrivers();
        
        // 筛选在配送范围内的司机
        return onlineDrivers.stream()
            .filter(driver -> {
                Map<String, Double> driverLocation = Map.of(
                    "latitude", driver.getCurrentLatitude().doubleValue(),
                    "longitude", driver.getCurrentLongitude().doubleValue()
                );
                double distance = calculateDistance(driverLocation, orderLocation);
                return distance <= maxDistance;
            })
            .collect(Collectors.toList());
    }
    
    @Override
    public Double calculateDistance(Map<String, Double> driverLocation, Map<String, Double> orderLocation) {
        double lat1 = Math.toRadians(driverLocation.get("latitude"));
        double lon1 = Math.toRadians(driverLocation.get("longitude"));
        double lat2 = Math.toRadians(orderLocation.get("latitude"));
        double lon2 = Math.toRadians(orderLocation.get("longitude"));
        
        double dLat = lat2 - lat1;
        double dLon = lon2 - lon1;
        
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                  Math.cos(lat1) * Math.cos(lat2) *
                  Math.sin(dLon / 2) * Math.sin(dLon / 2);
        
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        
        return EARTH_RADIUS * c;
    }
    
    @Override
    public Double calculateMatchScore(DriverEntity driver, Long orderId, Map<String, Double> orderLocation, Map<String, Double> weights) {
        // 距离分数(距离越近分数越高)
        Map<String, Double> driverLocation = Map.of(
            "latitude", driver.getCurrentLatitude().doubleValue(),
            "longitude", driver.getCurrentLongitude().doubleValue()
        );
        double distance = calculateDistance(driverLocation, orderLocation);
        double distanceScore = Math.max(0, 100 - distance * 10); // 每公里扣10分
        
        // 评分分数
        double ratingScore = driver.getServiceRating().doubleValue() * 20; // 5分制转100分制
        
        // 负载分数(订单数越少分数越高)
        int currentOrders = getCurrentOrderCount(driver.getId());
        double loadScore = Math.max(0, 100 - currentOrders * 20); // 每个订单扣20分
        
        // 综合分数计算
        double totalScore = distanceScore * weights.getOrDefault("distance", 0.4) +
                           ratingScore * weights.getOrDefault("rating", 0.3) +
                           loadScore * weights.getOrDefault("load", 0.3);
        
        return Math.min(100.0, Math.max(0.0, totalScore));
    }
    
    @Override
    @Transactional
    public DispatchRecordEntity executeDispatch(Long orderId, Long driverId, Integer algorithmType, 
                                              Double matchScore, Double distance) {
        log.info("执行派单操作，订单ID: {}, 司机ID: {}, 算法类型: {}", orderId, driverId, algorithmType);
        
        DispatchRecordEntity record = new DispatchRecordEntity();
        record.setOrderId(orderId);
        record.setDriverId(driverId);
        record.setAssignType(0); // 0-自动派单
        record.setAssignTime(LocalDateTime.now());
        record.setPriority(3); // 默认中等优先级
        record.setDispatchStatus(0); // 0-待接单
        record.setMatchScore(BigDecimal.valueOf(matchScore).setScale(2, RoundingMode.HALF_UP));
        record.setDispatchDistance(BigDecimal.valueOf(distance).setScale(2, RoundingMode.HALF_UP));
        record.setAlgorithmType(algorithmType);
        record.setEstimatedArrivalTime(LocalDateTime.now().plusMinutes(30)); // 预计30分钟送达
        
        dispatchRecordMapper.insert(record);
        
        // TODO: 发送派单通知给司机
        
        return record;
    }
    
    @Override
    @Transactional
    public DispatchRecordEntity redispatch(Long dispatchRecordId, List<Long> excludeDriverIds) {
        log.info("重新派单，原派单记录ID: {}, 排除司机: {}", dispatchRecordId, excludeDriverIds);
        
        // 获取原派单记录
        DispatchRecordEntity originalRecord = dispatchRecordMapper.selectById(dispatchRecordId);
        if (originalRecord == null) {
            throw new RuntimeException("派单记录不存在");
        }
        
        // 取消原派单记录
        originalRecord.setDispatchStatus(3); // 3-已取消
        originalRecord.setCancelReason("重新派单");
        dispatchRecordMapper.updateById(originalRecord);
        
        // TODO: 重新执行派单逻辑，排除指定司机
        
        return null;
    }
    
    @Override
    @Transactional
    public Boolean cancelDispatch(Long dispatchRecordId, String cancelReason) {
        log.info("取消派单，派单记录ID: {}, 取消原因: {}", dispatchRecordId, cancelReason);
        
        DispatchRecordEntity record = dispatchRecordMapper.selectById(dispatchRecordId);
        if (record == null) {
            return false;
        }
        
        record.setDispatchStatus(3); // 3-已取消
        record.setCancelReason(cancelReason);
        
        return dispatchRecordMapper.updateById(record) > 0;
    }
    
    /**
     * 获取司机当前订单数量
     * TODO: 实现具体的查询逻辑
     */
    private int getCurrentOrderCount(Long driverId) {
        // 暂时返回随机数模拟
        return new Random().nextInt(5);
    }
}